import Q from './vendor/q';
import u from './vendor/underscore';
import helper from './vendor/helper';
import Queue from './queue';
import MimeType from './bce-sdk-js/mime.types';
import util from './vendor/util';
/**
 * 取得已上传分块的etag
 *
 * @param {number} partNumber 分片序号.
 * @param {Array} existParts 已上传完成的分片信息.
 * @return {string} 指定分片的etag
 */
function getPartEtag(partNumber, existParts) {
    var matchParts = u.filter(existParts || [], function (part) {
        return +part.partNumber === partNumber;
    });
    return matchParts.length ? matchParts[0].eTag : null;
}

export default {
    dumpError : typeof console === 'object' && typeof console.error === 'function'
    ? function (error) { console.error(error); }
    : u.noop,
    /**
     * 把文件进行切片，返回切片之后的数组
     * @param {Blob} file 需要切片的大文件.
     * @param {string} uploadId 从服务获取的uploadId.
     * @param {number} chunkSize 分片的大小.
     * @param {string} bucket Bucket Name.
     * @param {string} object Object Name.
     * @return {Array.<Object>}
     */
   getTasks : function (file, uploadId, chunkSize, bucket, object) {
    var leftSize = file.blob.byteLength;
    var offset = 0;
    var partNumber = 1;
    var tasks = [];
    while (leftSize > 0) {
        var partSize = Math.min(leftSize, chunkSize);
        tasks.push({
            file: file,
            uploadId: uploadId,
            bucket: bucket,
            object: object,
            partNumber: partNumber,
            partSize: partSize,
            start: offset,
            stop: offset + partSize - 1
        });
        leftSize -= partSize;
        offset += partSize;
        partNumber += 1;
    }
    return tasks;
},

getAppendableTasks : function (fileSize, offset, chunkSize) {
    var leftSize = fileSize - offset;
    var tasks = [];
    while (leftSize) {
        var partSize = Math.min(leftSize, chunkSize);
        tasks.push({
            partSize: partSize,
            start: offset,
            stop: offset + partSize - 1
        });

        leftSize -= partSize;
        offset += partSize;
    }
    return tasks;
},

parseSize : function (size) {
    if (typeof size === 'number') {
        return size;
    }
    // mb MB Mb M
    // kb KB kb k
    // 100
    var pattern = /^([\d\.]+)([mkg]?b?)$/i;
    var match = pattern.exec(size);
    if (!match) {
        return 0;
    }
    var $1 = match[1];
    var $2 = match[2];
    if (/^k/i.test($2)) {
        return $1 * 1024;
    }
    else if (/^m/i.test($2)) {
        return $1 * 1024 * 1024;
    }
    else if (/^g/i.test($2)) {
        return $1 * 1024 * 1024 * 1024;
    }
    return +$1;
},

/**
 * 判断一下浏览器是否支持 xhr2 特性，如果不支持，就 fallback 到 PostObject
 * 来上传文件
 *
 * @return {boolean}
 */
isXhr2Supported : function () {
    // https://github.com/Modernizr/Modernizr/blob/f839e2579da2c6331eaad922ae5cd691aac7ab62/feature-detects/network/xhr2.js
    return 'XMLHttpRequest' in window && 'withCredentials' in new XMLHttpRequest();
},

isAppendable : function (headers) {
    return headers['x-bce-object-type'] === 'Appendable';
},

delay : function (ms) {
    var deferred = Q.defer();
    setTimeout(function () {
        deferred.resolve();
    }, ms);
    return deferred.promise;
},

/**
 * 规范化用户的输入
 *
 * @param {string} endpoint The endpoint will be normalized
 * @return {string}
 */
normalizeEndpoint : function (endpoint) {
    return endpoint.replace(/(\/+)$/, '');
},

getDefaultACL : function (bucket) {
    return {
        accessControlList: [
            {
                service: 'bce:bos',
                region: '*',
                effect: 'Allow',
                resource: [bucket + '/*'],
                permission: ['READ', 'WRITE']
            }
        ]
    };
},

/**
 * 生成uuid
 *
 * @return {string}
 */
uuid : function () {
    var random = (Math.random() * Math.pow(2, 32)).toString(36);
    var timestamp = new Date().getTime();
    return 'u-' + timestamp + '-' + random;
},

/**
 * 生成本地 localStorage 中的key，来存储 uploadId
 * localStorage[key] = uploadId
 *
 * @param {Object} option 一些可以用来计算key的参数.
 * @param {string} generator 内置的只有 default 和 md5
 * @return {Promise}
 */
generateLocalKey : function (option, generator) {
    if (generator === 'default') {
        return Q.resolve([
            option.blob.name, option.blob.blob.byteLength,
            option.chunkSize, option.bucket,
            option.object
        ].join('&'));
    }
    return Q.resolve(null);
},

getDefaultPolicy : function (bucket) {
    if (bucket == null) {
        return null;
    }
    var now = new Date().getTime();
    // 默认是 24小时 之后到期
    var expiration = new Date(now + 24 * 60 * 60 * 1000);
    var utcDateTime = helper.toUTCString(expiration);
    return {
        expiration: utcDateTime,
        conditions: [
            {bucket: bucket}
        ]
    };
},

/**
 * 根据key获取localStorage中的uploadId
 * @param {string} key 需要查询的key
 * @return {string}
 */
getUploadId : function (key) {
    if(!localStorage){
      return wx.getStorageSync(key);
    }
    return localStorage.getItem(key);
},


/**
 * 根据key设置localStorage中的uploadId
 *
 * @param {string} key 需要查询的key
 * @param {string} uploadId 需要设置的uploadId
 */
setUploadId : function (key, uploadId) {
   if(!localStorage){
      wx.setStorageSync(key,uploadId);
   }else{
     localStorage.setItem(key, uploadId);
   }
},

/**
 * 根据key删除localStorage中的uploadId
 *
 * @param {string} key 需要查询的key
 */
  removeUploadId : function (key) {
  if (!localStorage) {
     wx.removeStorageSync(key);
  }else{
    localStorage.removeItem(key);
  }

},
/**
 * 因为 listParts 会返回 partNumber 和 etag 的对应关系
 * 所以 listParts 返回的结果，给 tasks 中合适的元素设置 etag 属性，上传
 * 的时候就可以跳过这些 part
 * @param {Array.<Object>} tasks 本地切分好的任务.
 * @param {Array.<Object>} parts 服务端返回的已经上传的parts.
 */
filterTasks : function (tasks, parts) {
    u.each(tasks, function (task) {
        var partNumber = task.partNumber;
        var etag = getPartEtag(partNumber, parts);
        if (etag) {
            task.etag = etag;
        }
    });
},

/**
 * 把用户输入的配置转化成 html5 和 flash 可以接收的内容.
 *
 * @param {string|Array} accept 支持数组和字符串的配置
 * @return {string}
 */
expandAccept : function (accept) {
    var exts = [];
    if (u.isArray(accept)) {
        // Flash要求的格式
        u.each(accept, function (item) {
            if (item.extensions) {
                exts.push.apply(exts, item.extensions.split(','));
            }
        });
    }
    else if (u.isString(accept)) {
        exts = accept.split(',');
    }
    // 为了保证兼容性，把 mimeTypes 和 exts 都返回回去
    exts = u.map(exts, function (ext) {
        return (/^\./.test(ext) || /\//.test(ext)) ? ext : ('.' + ext);
    });
    return exts.join(',');
},

extToMimeType : function (exts) {
    var mimeTypes = u.map(exts.split(','), function (ext) {
        if (ext.indexOf('/') !== -1) {
            return ext;
        }
        return MimeType.guess(ext);
    });

    return mimeTypes.join(',');
},

expandAcceptToArray : function (accept) {
    if (!accept || u.isArray(accept)) {
        return accept;
    }

    if (u.isString(accept)) {
        return [
            {title: 'All files', extensions: accept}
        ];
    }

    return [];
},

/**
 * 转化一下 bos url 的格式
 * http://bj.bcebos.com/v1/${bucket}/${object} -> http://${bucket}.bj.bcebos.com/v1/${object}
 * @param {string} url 需要转化的URL.
 * @return {string}
 */
transformUrl : function (url) {
    var pattern = /(https?:)\/\/([^\/]+)\/([^\/]+)\/([^\/]+)/;
    return url.replace(pattern, function (_, protocol, host, $3, $4) {
        if (/^v\d$/.test($3)) {
            // /v1/${bucket}/...
            return protocol + '//' + $4 + '.' + host + '/' + $3;
        }
        // /${bucket}/...
        return protocol + '//' + $3 + '.' + host + '/' + $4;
    });
},

isBlob : function (body) {
    var blobCtor = null;

    if (typeof Blob !== 'undefined') {
        // Chrome Blob === 'function'
        // Safari Blob === 'undefined'
        blobCtor = Blob;
    }
    else if (typeof mOxie !== 'undefined' && u.isFunction(mOxie.Blob)) {
        blobCtor = mOxie.Blob;
    }
    else {
        return false;
    }

    return body instanceof blobCtor;
},

now : function () {
    return new Date().getTime();
},

toDHMS : function (seconds) {
    var days = 0;
    var hours = 0;
    var minutes = 0;

    if (seconds >= 60) {
        minutes = ~~(seconds / 60);
        seconds = seconds - minutes * 60;
    }

    if (minutes >= 60) {
        hours = ~~(minutes / 60);
        minutes = minutes - hours * 60;
    }

    if (hours >= 24) {
        days = ~~(hours / 24);
        hours = hours - days * 24;
    }

    return {DD: days, HH: hours, MM: minutes, SS: seconds};
},
eachLimit : function (tasks, taskParallel, executer, done) {
    var runningCount = 0;
    var aborted = false;
    var fin = false; // done 只能被调用一次.
    var queue = new Queue(tasks);
    function infiniteLoop() {
        var task = queue.dequeue();
        if (!task) {
            return;
        }
        runningCount++;
        executer(task, function (error) {
            runningCount--;
            if (error) {
                // 一旦有报错，终止运行
                aborted = true;
                fin = true;
                done(error);
            }
            else {
                if (!queue.isEmpty() && !aborted) {
                    // 队列还有内容
                    setTimeout(infiniteLoop, 0);
                }
                else if (runningCount <= 0) {
                    // 队列空了，而且没有运行中的任务了
                    if (!fin) {
                        fin = true;
                        done();
                    }
                }
            }
        });
    }
    taskParallel = Math.min(taskParallel, queue.size());
    for (var i = 0; i < taskParallel; i++) {
        infiniteLoop();
    }
},

inherits :  function (ChildCtor, ParentCtor) {
    return util.inherits(ChildCtor, ParentCtor);
},

guessContentType : function (file, opt_ignoreCharset) {
    var contentType = file.type;
    if (!contentType) {
        var object = file.name;
        var ext = object.split(/\./g).pop();
        contentType = MimeType.guess(ext);
    }
    return contentType;
}

};
